/*
 * Logging.cpp
 * Author: ehpalumbo
 */

#include "Logging.h"
#include <iostream>


namespace logging {

const char* getLevelName(Level aLevel) {
	switch (aLevel) {
	case OFF: return "OFF";
	case TRACE: return "TRACE";
	case DEBUG: return "DEBUG";
	case INFO: return "INFO";
	case WARN: return "WARN";
	case ERROR: return "ERROR";
	case FATAL: return "FATAL";
	}
	return "";
}


LoggerImpl::LoggerImpl(const char* name, Level threshold) {
	this->threshold = threshold;
	this->name = name;
}

void LoggerImpl::log(Level detailLevel, const char* aMessage) {
	if (detailLevel >= this->threshold) {
		if (detailLevel > INFO) {
			cerr << "(" << getLevelName(detailLevel) << ") - {" << this->name << "} - " << aMessage << endl;
		} else {
			cout << "(" << getLevelName(detailLevel) << ") - {" << this->name << "} - " << aMessage << endl;
		}
	}
}

void LoggerImpl::log(Level detailLevel, const string& aMessage) {
	log(detailLevel, aMessage.c_str());
};

void LoggerImpl::log(Level detailLevel, const char* aMessage, const exception& thrown) {
	log(detailLevel, aMessage);
	log(detailLevel, thrown.what());
}

void LoggerImpl::log(Level detailLevel, const string& aMessage, const exception& thrown) {
	log(detailLevel, aMessage.c_str(), thrown);
}

void LoggerImpl::setThresholdLevel(Level threshold) {
	this->threshold = threshold;
}

LoggerImpl::~LoggerImpl() {
}

// LoggerFactory (implemented as Singleton)

LoggerFactory* LoggerFactory::instance;

LoggerFactory::LoggerFactory() {
	this->applicationLevel = INFO;
	this->loggers = new map<string, Logger*>;
	this->rootLogger = NULL;
}

void LoggerFactory::setApplicationLevel(Level decidedLevel) {
	this->applicationLevel = decidedLevel;
	if (this->rootLogger != NULL) {
		this->rootLogger->setThresholdLevel(decidedLevel);
	}
	string message = "Application Logging Level: ";
	getRootLogger().log(logging::DEBUG, message + getLevelName(decidedLevel) + ".");
}

Logger& LoggerFactory::getRootLogger() {
	if (this->rootLogger == NULL) {
		this->rootLogger = new LoggerImpl("default", this->applicationLevel);
	}
	return *(this->rootLogger);
}

Logger& LoggerFactory::getLogger(const string& loggerName) {
	if (loggerName == "default") return getRootLogger();
	map<string, Logger*>::iterator it = this->loggers->find(loggerName);
	if (it != this->loggers->end()) {
		return *((*it).second);
	} else {
		LoggerImpl* aNewLogger = new LoggerImpl(loggerName.c_str(), this->applicationLevel);
		this->loggers->insert(pair<string, Logger*>(loggerName, aNewLogger));
		return *aNewLogger;
	}
}

Logger& LoggerFactory::getLogger(const char* loggerName) {
	string ln(loggerName);
	return getLogger(ln);
}

LoggerFactory::~LoggerFactory() {
	delete this->rootLogger;
	for (map<string, Logger*>::iterator it = this->loggers->begin(); it != this->loggers->end(); it++) {
		delete (*it).second;
	}
	this->loggers->clear();
	delete this->loggers;
}

LoggerFactory& LoggerFactory::getInstance() {
	if (instance == NULL) {
		instance = new LoggerFactory();
	}
	return (*instance);
}

void LoggerFactory::shutdownLogging() {
	delete instance;
}

}
